#include "../common/head.h"
#include "../common/thread_pool.h"
#include "../common/common.h"
#include "../common/udp_server.h" 
#include "../common/udp_epoll.h"
#include "../common/sub_reactor.h"
#include "../common/heart_beat.h"
#include "../common/game.h"
#include "../common/server_exit.h"
#include "../common/server_re_drew.h"
#include "../common/show_data_stream.h"
#include "../common/ball_status.h"

char *conf = "./server.conf";

struct User *rteam;
struct User *bteam;
struct Bpoint ball;
struct BallStatus ball_status;

int repollfd, bepollfd;
int data_port;
int port = 0;

//struct Map court;

int main(int argc, char **argv) {
	setlocale(LC_ALL,"");//设置地域,解决乱码， 提高兼容性
	int opt, listener, epoll_fd; 
    pthread_t draw_t, red_t, blue_t, heart_t;
    while ((opt = getopt(argc, argv, "p:")) != -1) {
        switch (opt) {
            case 'p':
                port = atoi(optarg);//-p 指定端口
                break;
            default:
                fprintf(stderr, "Usage: %s [-p port]\n", argv[0]);
                exit(1);
        }
    }
    argc -= (optind - 1);//个数减少
    argv += (optind - 1);//指针后移动

    if (argc > 1) {//参数多
        fprintf(stderr, "Usage: %s [-p port]\n", argv[0]);
        exit(1);
    }

    if (!port) port = atoi(get_value(conf, "PORT"));//前面没有指定的时候，自己获取port
    data_port = atoi(get_value(conf, "DATAPORT"));//获取data_port
    court.width = atoi(get_value(conf, "COLS"));//获取球场的宽度
    court.height = atoi(get_value(conf, "LINES"));//获取球场的高度
    court.start.x = 3;//获取球场的起始位置x
    court.start.y = 3;//获取球场的起始位置y
	ball.x = court.width / 2;//球的位置
	ball.y = court.height / 2;//球的位置

    rteam = (struct User *)calloc(MAX, sizeof(struct User));//红队数组
    bteam = (struct User *)calloc(MAX, sizeof(struct User));//蓝队数组

    if ((listener = socket_create_udp(port)) < 0) {//获取一个套接字
        perror("socket_create_udp");
        exit(1);
    }

    DBG(GREEN"INFO"NONE" : Server start on Port %d\n", port);
#ifndef _D
    pthread_create(&draw_t, NULL, draw, NULL);//绘制界面的线程
#endif

    epoll_fd = epoll_create(MAX * 2);//主反应堆句柄，主反应堆2倍
    repollfd = epoll_create(MAX);//红队反应堆句柄
    bepollfd = epoll_create(MAX);//蓝队反应堆句柄

    if (epoll_fd < 0 || repollfd < 0 || bepollfd < 0) {//如果有一个反应堆创建失败结束
        perror("epoll_create");
        exit(1);
    }

	struct task_queue redQueue;//红队任务队列
	struct task_queue blueQueue;//蓝队任务队列

	task_queue_init(&redQueue, MAX, repollfd);//任务队列初始化，将epoll句柄加入
	task_queue_init(&blueQueue, MAX, bepollfd);

	pthread_create(&red_t, NULL, sub_reactor, (void *)&redQueue);//红队任务队列在从反应堆中的线程
	pthread_create(&blue_t, NULL, sub_reactor, (void *)&blueQueue);//蓝队任务队列中反应堆中的线程 
	pthread_create(&heart_t, NULL, heart_beat, NULL);//心跳线程，为了下线长时间无响应的客户端
		
	signal(SIGINT, server_exit);//当收到SIGINT信号的时候进行关闭服务器

    struct epoll_event ev, events[MAX * 2];//结构体和数组
    ev.events = EPOLLIN;/*关注来的事件*/
    ev.data.fd = listener;//描述符
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listener, &ev);//关注的事件放在epoll_fd,将listener加入
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    
	signal(14, re_drew);
	
	struct itimerval itimer;
	itimer.it_interval.tv_sec = 0;
	itimer.it_interval.tv_usec = 50000;
	itimer.it_value.tv_sec = 1;
	itimer.it_value.tv_usec = 0;

	setitimer(ITIMER_REAL, &itimer, NULL);

	Show_Message(, , "Waiting for Login", 1);

    while (1) {
		DBG(YELLOW"Main Pthread"NONE" :  before epoll_wait\n");
        int nfds = epoll_wait(epoll_fd, events, MAX * 2, -1);//返回就绪的数量，放到events数组中
        DBG(YELLOW"Main Pthread"NONE" :  After epoll_wait\n");

        for (int i = 0; i < nfds; i++) {
			struct User user;
            char buff[512] = {0};
            DBG(YELLOW"EPOLL"NONE" :  Doing with %dth fd\n", i);
            if (events[i].data.fd == listener) {//如果是初始的那个文件描述符，就继续监听登录
                //accept();
                int new_fd = udp_accept(epoll_fd, listener, &user);//返回的新的链接套接字，新的用户信息user
				if (new_fd > 0) {//通过判断是否有新的用户链接，进行将User加入对应反应堆
					DBG(YELLOW"Main thread"NONE" : Add %s to %s sub_reactor.\n", user.name, (user.team ? "BLUE": "RED"));
					add_to_sub_reactor(&user);//将新的用户信息加入到对应从反应堆的epoll进行继续监听
					show_data_stream('l');
					sprintf(buff, "%s login the Game.", user.name);
					Show_Message( , , buff, 1);
				}
            } else {
                recv(events[i].data.fd, buff, sizeof(buff), 0);//收到的数据
                DBG(PINK"RECV"NONE" : %s\n", buff);
            }
            //char info[1024] = {0};
            //w_gotoxy_puts(Message, 1, 2, info);
        }

    }
    return 0;
}
